Populating the search field
Our list of suggestions doesn't
do us much good if we can't place them in the search box. To begin
with, we'll allow a mouse click to confirm a suggestion:
'success': function(data) {
if (data.length) {
$autocomplete.empty();
$.each(data, function(index, term) {
$('<li></li>').text(term)
.appendTo($autocomplete)
.click(function() {
$('#search-text').val(term);
$autocomplete.hide();
});
});
$autocomplete.show();
}
}
This modification sets the
text of the search box to whatever list item was clicked. We also hide
the suggestions after this since we are done with them.
Keyboard navigation
Since the user is already at
the keyboard, and typing in the search term, it is very convenient to
allow the keyboard to control selection from the suggestion list as
well. We'll need to keep track of the currently selected item to enable
this. First, we can add a helper function that will store the index of
the item and perform the necessary visual effects to reveal which item
is currently selected:
var selectedItem = null;
var setSelectedItem = function(item) {
selectedItem = item;
if (selectedItem === null) {
$autocomplete.hide();
return;
}
if (selectedItem < 0) {
selectedItem = 0;
}
if (selectedItem >= $autocomplete.find('li').length) {
selectedItem = $autocomplete.find('li').length - 1;
}
$autocomplete.find('li').removeClass('selected')
.eq(selectedItem).addClass('selected');
$autocomplete.show();
};
The selectedItem variable will be set to null whenever no item is selected. By always calling setSelectedItem() to change the value of the variable, we can be sure that the suggestion list is only visible when there is a selected item.
The two tests for the numeric value of selectedItem are present to clamp the results to the appropriate range. Without these tests, selectedItem could end up with any value, even negative ones. This function ensures that the current value of selectedItem is always a valid index in the list of suggestions.
We can now revise our existing code to use the new function:
$('#search-text').attr('autocomplete', 'off').keyup(function() {
$.ajax({
'url': '../search/autocomplete.php',
'data': {'search-text': $('#search-text').val()},
'dataType': 'json',
'type': 'GET',
'success': function(data) {
if (data.length) {
$autocomplete.empty();
$.each(data, function(index, term) {
$('<li></li>').text(term)
.appendTo($autocomplete)
.mouseover(function() {
setSelectedItem(index);
})
.click(function() {
$('#search-text').val(term);
$autocomplete.hide();
});
});
setSelectedItem(0);
}
else {
setSelectedItem(null);
}
}
});
});
This revision has
several immediate benefits. First, the suggestion list is hidden when
there are no results for a given search. Second, we are able to add a mouseover
handler that highlights the item under the mouse cursor. Third, the
first item is highlighted immediately when the suggestion list is shown:
Now we need to allow the keyboard keys to change which item is currently active in the list.